import * as Cesium from "cesium";

const viewer = new Cesium.Viewer("cesiumContainer", {
  terrain: Cesium.Terrain.fromWorldTerrain(),
  animation: false,
  timeline: false,
});

// More datasets to tour can be added here...
// The url passed to I3SDataProvider supports loading a single Indexed 3D Scene (I3S) layer (.<host>/SceneServer/layers/<id>) or a collection of scene layers (.<host>/SceneServer) from a SceneServer.
const tours = {
  "San Francisco":
    "https://tiles.arcgis.com/tiles/z2tnIkrLQ2BRzr6P/arcgis/rest/services/SanFrancisco_3DObjects_1_7/SceneServer/layers/0",
};

try {
  // Initialize a terrain provider which provides geoid conversion between gravity related (typically I3S datasets) and ellipsoidal based
  // height systems (Cesium World Terrain).
  // If this is not specified, or the URL is invalid no geoid conversion will be applied.
  // The source data used in this transcoding service was compiled from https://earth-info.nga.mil/#tab_wgs84-data and is based on EGM2008 Gravity Model
  const geoidService = await Cesium.ArcGISTiledElevationTerrainProvider.fromUrl(
    "https://tiles.arcgis.com/tiles/z2tnIkrLQ2BRzr6P/arcgis/rest/services/EGM2008/ImageServer",
  );
  // Create i3s options to pass optional parameters useful for debugging and visualizing
  const i3sOptions = {
    geoidTiledTerrainProvider: geoidService, // pass the geoid service
  };

  // Create I3S data provider
  const i3sProvider = await Cesium.I3SDataProvider.fromUrl(
    tours["San Francisco"],
    i3sOptions,
  );

  // Add the i3s layer provider as a primitive data type
  viewer.scene.primitives.add(i3sProvider);

  // Center camera on I3S once it's loaded
  const center = Cesium.Rectangle.center(i3sProvider.extent);
  center.height = 5000.0;
  viewer.camera.setView({
    destination: Cesium.Ellipsoid.WGS84.cartographicToCartesian(center),
  });
} catch (error) {
  console.log(`There was an error creating the I3S Data Provider: ${error}`);
}

// An entity object which will hold info about the currently selected feature for infobox display
const selectedEntity = new Cesium.Entity();
// Show metadata in the InfoBox.
viewer.screenSpaceEventHandler.setInputAction(function onLeftClick(movement) {
  // Pick a new feature
  const pickedFeature = viewer.scene.pick(movement.position);
  if (!Cesium.defined(pickedFeature)) {
    return;
  }

  const pickedPosition = viewer.scene.pickPosition(movement.position);

  if (
    Cesium.defined(pickedFeature.content) &&
    Cesium.defined(pickedFeature.content.tile.i3sNode)
  ) {
    const i3sNode = pickedFeature.content.tile.i3sNode;
    if (pickedPosition) {
      i3sNode.loadFields().then(function () {
        let description = "No attributes";
        let name;

        const fields = i3sNode.getFieldsForPickedPosition(pickedPosition);
        if (Object.keys(fields).length > 0) {
          description = '<table class="cesium-infoBox-defaultTable"><tbody>';
          for (const fieldName in fields) {
            if (i3sNode.fields.hasOwnProperty(fieldName)) {
              description += `<tr><th>${fieldName}</th><td>`;
              description += `${fields[fieldName]}</td></tr>`;
              if (!Cesium.defined(name) && isNameProperty(fieldName)) {
                name = fields[fieldName];
              }
            }
          }
          description += `</tbody></table>`;
        }
        if (!Cesium.defined(name)) {
          name = "unknown";
        }
        selectedEntity.name = name;
        selectedEntity.description = description;
        viewer.selectedEntity = selectedEntity;
      });
    }
  }
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);

function isNameProperty(propertyName) {
  const name = propertyName.toLowerCase();
  if (name.localeCompare("name") === 0 || name.localeCompare("objname") === 0) {
    return true;
  }
  return false;
}
